package formatter

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/goccy/go-json"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

type LargeJsonFormatter struct {
	filename string
	indent   string
	verbose  bool
}

func NewLargeJsonFormatter(filename string, indent string, verbose bool) (*LargeJsonFormatter, error) {
	if filename == "" {
		return nil, errors.New("文件名不能为空")
	}
	return &LargeJsonFormatter{
		filename: filename,
		indent:   indent,
		verbose:  verbose,
	}, nil
}

func (ft *LargeJsonFormatter) Format() {
	if f, err := os.Open(ft.filename); err != nil {
		ft.println(true, "打开文件失败 ", err)
	} else {
		defer func(f *os.File) {
			_ = f.Close()
		}(f)
		if fi, err := os.Stat(ft.filename); err != nil {
			ft.println(true, "读取文件失败 ", err)
		} else {
			ft.printf(false, "获得文件详细信息完毕，%s", fi.Name())
			startTime := time.Now()
			buf := make([]byte, fi.Size())
			doneBytesCount := 0
			if n, err := f.Read(buf); err != nil {
				ft.println(true, "读取文件失败 ", err)
			} else {
				ft.printf(false, "读取文件完毕，共%d字节（%s）", n, ft.friendly(n))
				buf = bytes.Trim(buf, "\n")
				if buf[0] == '{' && buf[len(buf)-1] == '}' {
					doneBytesCount = ft.parseAsObject(buf)
				} else if buf[0] == '[' && buf[len(buf)-1] == ']' {
					doneBytesCount = ft.parseAsArray(buf)
				} else {
					ft.println(true, "文本内容无法识别，可能不是有效的JSON ", err)
					return
				}
				ft.printf(false, "格式化JSON文件完成，大小 %s，耗时 %s", ft.friendly(doneBytesCount), time.Now().Sub(startTime))
			}
		}
	}
}

func (ft *LargeJsonFormatter) parseAsObject(buf []byte) int {
	tmpObj := make(map[string]interface{}, len(buf)%1000+1000)
	outBuf := make([]byte, len(buf))
	if err := json.Unmarshal(buf, &tmpObj); err != nil {
		ft.println(true, "解析文件JSON内容失败 ", err)
	} else {
		ft.printf(false, "文件内容解码完毕，一级项 %d 个", len(tmpObj))
		if outBuf, err = json.MarshalIndent(tmpObj, "", ft.indent); err != nil {
			ft.println(true, "解析文件JSON内容失败 ", err)
		} else {
			ft.printf(false, "文件内容转码完毕，将结果写入目标文件")
			if err = os.WriteFile(ft.getTargetFilename(), outBuf, 0666); err != nil {
				ft.println(true, "保存格式化之后的JSON内容失败 ", err)
			} else {
				return len(outBuf)
			}
		}
	}
	return -1
}

func (ft *LargeJsonFormatter) parseAsArray(buf []byte) int {
	tmpObj := make([]map[string]interface{}, len(buf)%1000+1000)
	outBuf := make([]byte, len(buf))
	if err := json.Unmarshal(buf, &tmpObj); err != nil {
		ft.println(true, "解析文件JSON内容失败 ", err)
	} else {
		ft.printf(false, "文件内容解码完毕，一级项 %d 个", len(tmpObj))
		if outBuf, err = json.MarshalIndent(tmpObj, "", ft.indent); err != nil {
			ft.println(true, "解析文件JSON内容失败 ", err)
		} else {
			ft.printf(false, "文件内容转码完毕，将结果写入目标文件")
			if err = os.WriteFile(ft.getTargetFilename(), outBuf, 0666); err != nil {
				ft.println(true, "保存格式化之后的JSON内容失败 ", err)
			} else {
				return len(outBuf)
			}
		}
	}
	return -1
}

func (ft *LargeJsonFormatter) getTargetFilename() string {
	t := time.Now().Format("2006-01-02_15-04-05")
	// 获取文件的基本名称
	baseName := filepath.Base(ft.filename)

	// 去除文件扩展名
	mainFileName := strings.TrimSuffix(baseName, filepath.Ext(ft.filename))
	return path.Join(path.Dir(ft.filename), mainFileName+"_"+t+"_formatted"+path.Ext(ft.filename))
}

func (ft *LargeJsonFormatter) println(forceVerbose bool, a ...any) {
	if forceVerbose {
		fmt.Println(a...)
	} else {
		if ft.verbose {
			log.Println(a...)
		}
	}
}

func (ft *LargeJsonFormatter) printf(forceVerbose bool, format string, a ...any) {
	if forceVerbose {
		fmt.Printf(format, a...)
	} else {
		if ft.verbose {
			log.Printf(format, a...)
		}
	}
}

func (ft *LargeJsonFormatter) friendly(n int) string {
	if n < 1024 {
		return fmt.Sprintf("%dbytes", n)
	} else if n < 1024*1024 {
		return fmt.Sprintf("%.2fKB", float64(n)/1024)
	} else if n < 1024*1024*1024 {
		return fmt.Sprintf("%.3fMB", float64(n)/1024/1024)
	} else {
		return fmt.Sprintf("%.4fGB", float64(n)/1024/1024/1024)
	}
}
